import fs from 'fs-extra'
import * as path from 'path'
import * as os from 'os'
import { randomUUID, createHash } from 'crypto'

export interface PMConfig {
  prdFilePath?: string
  outputDirectory?: string
  lastUsedPrompts?: string[]
  userPreferences?: {
    language?: 'zh-CN' | 'en-US'
    theme?: 'light' | 'dark'
  }
  sessionId?: string
  createdAt?: string
  lastUsedAt?: string
}

export interface SessionInfo {
  sessionId: string
  userId?: string
  projectPath?: string
  createdAt: string
  lastUsedAt: string
}

export class SessionConfigManager {
  private configDir: string
  private sessionsDir: string
  private sessionId: string
  private config: PMConfig
  private sessionInfo: SessionInfo

  constructor(sessionId?: string, userId?: string, projectPath?: string) {
    // 配置目录结构
    this.configDir = path.join(os.homedir(), '.funi-mcp')
    this.sessionsDir = path.join(this.configDir, 'sessions')
    
    // 生成或使用提供的会话ID
    this.sessionId = sessionId || this.generateSessionId(userId, projectPath)
    
    // 初始化会话信息
    this.sessionInfo = {
      sessionId: this.sessionId,
      userId,
      projectPath,
      createdAt: new Date().toISOString(),
      lastUsedAt: new Date().toISOString()
    }
    
    this.config = {
      sessionId: this.sessionId,
      userPreferences: {
        language: 'zh-CN',
        theme: 'light'
      }
    }
  }

  /**
   * 生成会话ID
   */
  private generateSessionId(userId?: string, projectPath?: string): string {
    if (userId && projectPath) {
      // 基于用户ID和项目路径生成稳定的会话ID
      const hash = createHash('md5')
      hash.update(`${userId}-${projectPath}`)
      return hash.digest('hex').substring(0, 16)
    }
    // 生成随机会话ID
    return randomUUID().replace(/-/g, '').substring(0, 16)
  }

  /**
   * 获取会话配置文件路径
   */
  private getSessionConfigPath(): string {
    return path.join(this.sessionsDir, `${this.sessionId}.json`)
  }

  /**
   * 获取会话信息文件路径
   */
  private getSessionInfoPath(): string {
    return path.join(this.sessionsDir, `${this.sessionId}.info.json`)
  }

  /**
   * 加载会话配置
   */
  async loadConfig(): Promise<PMConfig> {
    try {
      await fs.ensureDir(this.sessionsDir)
      
      const configPath = this.getSessionConfigPath()
      const infoPath = this.getSessionInfoPath()
      
      // 加载配置文件
      if (await fs.pathExists(configPath)) {
        const configData = await fs.readFile(configPath, 'utf-8')
        this.config = { ...this.config, ...JSON.parse(configData) }
      }
      
      // 加载会话信息
      if (await fs.pathExists(infoPath)) {
        const infoData = await fs.readFile(infoPath, 'utf-8')
        this.sessionInfo = { ...this.sessionInfo, ...JSON.parse(infoData) }
      }
      
      // 更新最后使用时间
      this.sessionInfo.lastUsedAt = new Date().toISOString()
      await this.saveSessionInfo()
      
      return this.config
    } catch (error) {
      throw new Error(`加载会话配置失败: ${error instanceof Error ? error.message : '未知错误'}`)
    }
  }

  /**
   * 保存会话配置
   */
  async saveConfig(): Promise<void> {
    try {
      await fs.ensureDir(this.sessionsDir)
      
      const configPath = this.getSessionConfigPath()
      this.config.sessionId = this.sessionId
      
      await fs.writeFile(configPath, JSON.stringify(this.config, null, 2), 'utf-8')
      await this.saveSessionInfo()
    } catch (error) {
      throw new Error(`保存会话配置失败: ${error instanceof Error ? error.message : '未知错误'}`)
    }
  }

  /**
   * 保存会话信息
   */
  private async saveSessionInfo(): Promise<void> {
    const infoPath = this.getSessionInfoPath()
    this.sessionInfo.lastUsedAt = new Date().toISOString()
    await fs.writeFile(infoPath, JSON.stringify(this.sessionInfo, null, 2), 'utf-8')
  }

  /**
   * 设置 PRD 文件路径
   */
  async setPrdFilePath(filePath: string): Promise<void> {
    if (!await fs.pathExists(filePath)) {
      throw new Error(`PRD 文件不存在: ${filePath}`)
    }
    this.config.prdFilePath = filePath
    await this.saveConfig()
  }

  /**
   * 设置输出目录
   */
  async setOutputDirectory(directory: string): Promise<void> {
    await fs.ensureDir(directory)
    this.config.outputDirectory = directory
    await this.saveConfig()
  }

  /**
   * 获取 PRD 文件路径
   */
  getPrdFilePath(): string | undefined {
    return this.config.prdFilePath
  }

  /**
   * 获取输出目录
   */
  getOutputDirectory(): string | undefined {
    return this.config.outputDirectory
  }

  /**
   * 获取会话ID
   */
  getSessionId(): string {
    return this.sessionId
  }

  /**
   * 获取会话信息
   */
  getSessionInfo(): SessionInfo {
    return { ...this.sessionInfo }
  }

  /**
   * 添加最近使用的提示词
   */
  async addRecentPrompt(promptPath: string): Promise<void> {
    if (!this.config.lastUsedPrompts) {
      this.config.lastUsedPrompts = []
    }

    this.config.lastUsedPrompts = this.config.lastUsedPrompts.filter(p => p !== promptPath)
    this.config.lastUsedPrompts.unshift(promptPath)
    this.config.lastUsedPrompts = this.config.lastUsedPrompts.slice(0, 10)
    
    await this.saveConfig()
  }

  /**
   * 获取最近使用的提示词
   */
  getRecentPrompts(): string[] {
    return this.config.lastUsedPrompts || []
  }

  /**
   * 检查配置是否完整
   */
  isConfigComplete(): boolean {
    return !!(this.config.prdFilePath && this.config.outputDirectory)
  }

  /**
   * 获取配置状态信息
   */
  getConfigStatus(): {
    sessionId: string
    hasPrdFile: boolean
    hasOutputDir: boolean
    prdFilePath?: string
    outputDirectory?: string
    isComplete: boolean
    sessionInfo: SessionInfo
  } {
    return {
      sessionId: this.sessionId,
      hasPrdFile: !!this.config.prdFilePath,
      hasOutputDir: !!this.config.outputDirectory,
      prdFilePath: this.config.prdFilePath,
      outputDirectory: this.config.outputDirectory,
      isComplete: this.isConfigComplete(),
      sessionInfo: this.getSessionInfo()
    }
  }

  /**
   * 清理过期会话
   */
  static async cleanupExpiredSessions(maxAgeHours: number = 24): Promise<number> {
    try {
      const configDir = path.join(os.homedir(), '.funi-mcp')
      const sessionsDir = path.join(configDir, 'sessions')
      
      if (!await fs.pathExists(sessionsDir)) {
        return 0
      }

      const files = await fs.readdir(sessionsDir)
      const infoFiles = files.filter(f => f.endsWith('.info.json'))
      
      let cleanedCount = 0
      const cutoffTime = new Date(Date.now() - maxAgeHours * 60 * 60 * 1000)

      for (const infoFile of infoFiles) {
        const infoPath = path.join(sessionsDir, infoFile)
        const sessionId = infoFile.replace('.info.json', '')
        
        try {
          const infoData = await fs.readFile(infoPath, 'utf-8')
          const sessionInfo: SessionInfo = JSON.parse(infoData)
          
          if (new Date(sessionInfo.lastUsedAt) < cutoffTime) {
            // 删除会话配置和信息文件
            const configPath = path.join(sessionsDir, `${sessionId}.json`)
            
            await fs.remove(infoPath)
            if (await fs.pathExists(configPath)) {
              await fs.remove(configPath)
            }
            
            cleanedCount++
          }
        } catch (error) {
          // 如果文件损坏，也删除它
          await fs.remove(infoPath)
          cleanedCount++
        }
      }

      return cleanedCount
    } catch (error) {
      throw new Error(`清理过期会话失败: ${error instanceof Error ? error.message : '未知错误'}`)
    }
  }

  /**
   * 列出所有活跃会话
   */
  static async listActiveSessions(): Promise<SessionInfo[]> {
    try {
      const configDir = path.join(os.homedir(), '.funi-mcp')
      const sessionsDir = path.join(configDir, 'sessions')
      
      if (!await fs.pathExists(sessionsDir)) {
        return []
      }

      const files = await fs.readdir(sessionsDir)
      const infoFiles = files.filter(f => f.endsWith('.info.json'))
      
      const sessions: SessionInfo[] = []

      for (const infoFile of infoFiles) {
        try {
          const infoPath = path.join(sessionsDir, infoFile)
          const infoData = await fs.readFile(infoPath, 'utf-8')
          const sessionInfo: SessionInfo = JSON.parse(infoData)
          sessions.push(sessionInfo)
        } catch (error) {
          // 忽略损坏的文件
        }
      }

      // 按最后使用时间排序
      return sessions.sort((a, b) => 
        new Date(b.lastUsedAt).getTime() - new Date(a.lastUsedAt).getTime()
      )
    } catch (error) {
      throw new Error(`列出活跃会话失败: ${error instanceof Error ? error.message : '未知错误'}`)
    }
  }
}
